home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Environments / Clean 1.2.4 / IOInterface / scrollList.icl < prev    next >
Encoding:
Modula Implementation  |  1997-04-23  |  16.1 KB  |  476 lines  |  [TEXT/3PRM]

  1. implementation module scrollList;
  2.  
  3. /* General Scrolling List implementation. */
  4.  
  5. import StdClass, StdInt, StdString, StdChar, StdBool,StdArray;
  6. import deltaDialog, deltaEventIO, deltaTimer, deltaFont, deltaPicture, deltaSystem;
  7. import commonDef;
  8.  
  9. ::    NrVisible          :== Int;
  10.  
  11. ChangeI                :== 0;
  12. NrVisI                :== 1;
  13. WidthI                :== 2;
  14. FirstI                :== 4;
  15. DefltI                :== 6;
  16. FirstItemIndex        :== 8;
  17. ItemWid width        :== width - 13;
  18. DownTop nr ht        :== DownBot nr ht - ArrowHgt;
  19. DownBot nr ht        :== nr * ht;
  20. UpTop                :== 0;
  21. UpBot                :== ArrowHgt;
  22. ArrowHgt            :== 17;
  23. NoAction            :== '0';
  24. Selected            :== '1';
  25. ScrolledUp            :== '2';
  26. ScrolledDown        :== '3';
  27. EndOfList            :== '\\';        // there is no test on the value of EndOfList
  28.  
  29. ScrollListError :: String String Int -> * x;
  30. ScrollListError rule message id
  31.     =    Error rule "scrollList" (message +++ " (item id = " +++ toString id +++ ")");
  32.  
  33.  
  34. //
  35. //    The ScrollingList item definition.
  36. //
  37.  
  38. ScrollingList    ::    !DialogItemId !ItemPos !Measure !SelectState !NrVisible !ItemTitle ![ItemTitle]
  39.                     !(DialogFunction s (IOState s))
  40.                 ->    DialogItem s (IOState s);
  41. ScrollingList id pos minWidth select nrVisible defaultItem items dialogF
  42.     =    Control id pos ((-1,-1),(width,height)) select cState (ScrollLook font width at_new lineH)
  43.             (ScrollFeel width at_new lineH) (ScrollDFunc id dialogF);
  44.     where {
  45.         cState                = StringCS (SetWidth width sState);
  46.         (maxWidth, sState)    = InitScrollState font nrVisible defaultItem items;
  47.         width                = Max (MeasureToHorPixels minWidth) maxWidth + 20;
  48.         height                = inc (nrVisible * lineH);
  49.         lineH                = at_new + dt + ld;
  50.         (at_new, dt, mw, ld)= FontMetrics font;
  51.         (b, font)            = SelectFont name style size;
  52.         (name, style, size)    = DefaultFont;
  53.     };
  54.  
  55.  
  56. /*    The initial ControlState. */
  57.  
  58. InitScrollState :: !Font !Int !ItemTitle ![ItemTitle] -> (!Int, !String);
  59. InitScrollState font nrVisible defaultItem items
  60.     =    (maxWidth, SetNewFirst (nrVisible - realNrVisible) first state);
  61.     where {
  62.         (maxWidth,state)= CreateScrollState font nrVisible "" 0 False FirstItemIndex defaultItem items;
  63.         realNrVisible    = NrItemsVisible nrVisible 0 first state;
  64.         first            = GetFirstIndex state;
  65.     };
  66.  
  67. CreateScrollState :: !Font !Int !String !Int !Bool !Int !ItemTitle ![ItemTitle]
  68.     -> (!Int, !String);
  69. CreateScrollState font nrVisible state maxWidth found index defaultItem [item : items]
  70. |    found || defaultItem == item
  71.     = CreateScrollState font nrVisible state` maxWidth` True index defaultItem items;
  72.     = CreateScrollState font nrVisible state` maxWidth` found (index + length) defaultItem items;
  73.     where {
  74.         state`        = state +++ item +++ "\n";
  75.         maxWidth`    = Max maxWidth (FontStringWidth item font);
  76.         length        = inc (size item);
  77.     };
  78. CreateScrollState font nrVisible state maxWidth found index defaultItem items
  79. |    found
  80.     = (maxWidth, SetFirstIndex index (SetDefltIndex index state`));
  81.     = (maxWidth, SetFirstIndex FirstItemIndex (SetDefltIndex FirstItemIndex state`));
  82.     where {
  83.         state` = ((toString Selected +++ toString (toChar nrVisible)) +++ "      ") +++ state +++ toString EndOfList;
  84.     };
  85.  
  86. NrItemsVisible :: !Int !Int !Int !String -> Int;
  87. NrItemsVisible nrVisible itemNr index state
  88. |    nrVisible == 0 || noMore    = itemNr;
  89.                                 = NrItemsVisible (dec nrVisible) (inc itemNr) index` state;
  90.     where {
  91.         (noMore, index`, item)    = GetItem index state;
  92.     };
  93.  
  94. SetNewFirst    :: !Int !Int !String -> String;
  95. SetNewFirst itemNr index state
  96. |    itemNr <= 0 || noMore        = SetFirstIndex index state;
  97.                                 = SetNewFirst (dec itemNr) index` state;
  98.     where {
  99.         (noMore, index`, item)    = GetScrolledDownItem index state;
  100.     };
  101.  
  102.  
  103. /*    The ControlLook. */
  104.  
  105. ScrollLook :: !Font !Int !Int !Int !SelectState !ControlState -> [DrawFunction];
  106. ScrollLook font width ascent lineH select (StringCS state)
  107.     =    [frame,move,line,items : arrows];
  108.     where {
  109.         items        = DrawItemTitles able nrVisible ascent lineH first width defId state;
  110.         able        = Enabled select;
  111.         arrows        = DrawArrows width height select state;
  112.         frame        = DrawRectangle ((-1,-1), (width,height));
  113.         move        = MovePenTo (ItemWid width,-1);
  114.         line        = LinePen (0, height);
  115.         height        = inc (nrVisible * lineH);
  116.         nrVisible    = GetNrVis state;
  117.         first        = GetFirstIndex state;
  118.         defId        = GetDefltIndex state;
  119.     };
  120.  
  121. DrawArrows :: !Int !Int !SelectState !String -> [DrawFunction];
  122. DrawArrows width height Able state
  123. |    up && down        = [up1,up2,up3,down1,down2,down3];
  124. |    down            = [up1,up2,up3];
  125. |    up                = [down1,down2,down3];
  126.                     = [];
  127.     where {
  128.         (up, down)    = CanScroll state;
  129.         up1            = FillPolygon upArrow;
  130.         up2            = FillPolygon (MovePolygon (0,3) upArrow);
  131.         up3            = FillPolygon (MovePolygon (0,9) upArrow);
  132.         down1        = FillPolygon downArrow;
  133.         down2        = FillPolygon (MovePolygon (0,-3) downArrow);
  134.         down3        = FillPolygon (MovePolygon (0,-9) downArrow);
  135.         upArrow        = ((width - 7, 2), [(4,4), (-8,0)]);
  136.         downArrow    = ((width - 7, height - 3), [(-4,-4), (8,0)]);
  137.     };
  138. DrawArrows width height unable state
  139. |    up && down        = [up1,down1];
  140. |    down            = [up1];
  141. |    up                = [down1];
  142.                     = [];
  143.     where {
  144.         (up, down)    = CanScroll state;
  145.         up1            = DrawPolygon ((width - 7, 2), [(4,4), (-8,0)]);
  146.         down1        = DrawPolygon ((width - 7, height - 3), [(-4,-4), (8,0)]);
  147.     };
  148.  
  149. DrawItemTitles    :: !Bool !Int !Int !Int !Int !Int !Int !String !Picture -> Picture;
  150. DrawItemTitles able nr base lineH index width defId state pic
  151. |    nr == 0 || noMore        = pic;
  152. |    defItem && able            = DrawItemTitles able (dec nr) base` lineH index` width defId state pic1;
  153. |    defItem                    = DrawItemTitles able (dec nr) base` lineH index` width defId state pic2;
  154.                             = DrawItemTitles able (dec nr) base` lineH index` width defId state pic3;
  155.     where {
  156.         (noMore,index`,item)= GetItem index state;
  157.         pic1                = SelectItem        width defY lineH pic3;
  158.         pic2                = UnableSelectItem    width defY lineH pic3;
  159.         pic3                = DrawString item (MovePenTo (3,base) pic);
  160.         base`                = base + lineH;
  161.         defY                = base - base mod lineH;
  162.         defItem                = index == defId;
  163.     };
  164.  
  165. SelectItem :: !Int !Int !Int !Picture -> Picture;
  166. SelectItem width y lineH pic
  167.     =  SetPenMode CopyMode (
  168.             FillRectangle ((0,y),(ItemWid width, y + lineH)) (
  169.             SetPenMode HiliteMode pic));
  170.  
  171. UnableSelectItem :: !Int !Int !Int !Picture -> Picture;
  172. UnableSelectItem width y lineH pic
  173.     =  SetPenMode CopyMode (
  174.             DrawRectangle ((0,y),(ItemWid width, y + lineH)) (
  175.             SetPenMode HiliteMode pic));
  176.  
  177.  
  178. /*    The ControlFeel. */
  179.  
  180. ScrollFeel :: !Int !Int !Int !MouseState !ControlState -> (!ControlState, ![DrawFunction]);
  181. ScrollFeel width ascent lineH (pos, ButtonUp, mods) (StringCS state)
  182. |    action == ScrolledUp
  183. ||    action == ScrolledDown        = (state`, [erase : arrows]);
  184.                                 = (state`, []);
  185.     where {
  186.         state`    = StringCS (SetAction NoAction state);
  187.         erase    = EraseRectangle ((inc (ItemWid width), UpTop), (dec width, DownBot nrVis lineH));
  188.         arrows    = DrawArrows width (inc (nrVis * lineH)) Able state;
  189.         action    = GetAction state;
  190.         nrVis    = GetNrVis  state;
  191.     };
  192. ScrollFeel width ascent lineH ((x,y), ButtonStillDown, mods) (StringCS state)
  193. | action == ScrolledDown        = ScrollDown width ascent lineH nrVis y state;
  194. | action == ScrolledUp            = ScrollUp   width ascent lineH nrVis y state;
  195.                                 = (StringCS state`, []);
  196.     where {
  197.         state`    = SetAction NoAction state;
  198.         nrVis    = GetNrVis  state;
  199.         action    = GetAction state;
  200.     };
  201. ScrollFeel width ascent lineH ((x,y), buttonDown, mods) (StringCS state)
  202. |    InItemList  width lineH nrVis x y            = SelectNewItem defNr lineH width
  203.                                                     (SetAction NoAction state);
  204. |    OnUpArrow   width x y              && down    = (state1, [HiliteArrow width UpTop        : draws1]);
  205. |    OnDownArrow width lineH nrVis x y && up        = (state2, [HiliteArrow width downTop    : draws2]);
  206.                                                 = (StringCS (SetAction NoAction state), []);
  207.     where {
  208.         (state1, draws1)    = ScrollDown width ascent lineH nrVis y (SetAction ScrolledDown state);
  209.         (state2, draws2)    = ScrollUp   width ascent lineH nrVis y (SetAction ScrolledUp    state);
  210.         (up, down)            = CanScroll state;
  211.         downTop                = DownTop nrVis lineH;
  212.         nrVis                = GetNrVis state;
  213.         defNr                = y / lineH;
  214.     };
  215.  
  216. SelectNewItem :: !Int !Int !Int !String -> (!ControlState, ![DrawFunction]);
  217. SelectNewItem defNr lineH width state
  218. |    inList    = (StringCS state`, draws`);
  219.             = (StringCS state,  []);
  220.     where {
  221.         (inList,state`,draws)    = SelNewItem defNr 0 lineH first defId width state;
  222.         draws`                    = UnSelOldItem nrVis 0 lineH first defId width state` draws;
  223.         defId                    = GetDefltIndex state;
  224.         first                    = GetFirstIndex state;
  225.         nrVis                    = GetNrVis        state;
  226.     };
  227.  
  228. SelNewItem :: !Int !Int !Int !Int !Int !Int !String -> (!Bool, !String, ![DrawFunction]);
  229. SelNewItem nr y lineH index defId width state
  230. |    (found && index == defId) || noMore    = (False, state, []);
  231. |    found                                = (True, state`, [SelectItem width y lineH]);
  232.                                         = SelNewItem (dec nr) (y+lineH) lineH index` defId width state;
  233.     where {
  234.         (noMore, index`, item)    = GetItem index state;
  235.         found                    = nr == 0;
  236.         state`                    = SetAction Selected (SetDefltIndex index state);
  237.     };
  238.  
  239. UnSelOldItem :: !Int !Int !Int !Int !Int !Int !String ![DrawFunction] -> [DrawFunction];
  240. UnSelOldItem nr y lineH index defId width state draws
  241. |    nr == 0 || noMore    = draws;
  242. |    index == defId        = [SelectItem width y lineH : draws];
  243.                         = UnSelOldItem (dec nr) (y + lineH) lineH index` defId width state draws;
  244.     where {
  245.         (noMore, index`, item) = GetItem index state;
  246.     };
  247.  
  248. ScrollDown :: !Int !Int !Int !Int !Int !String -> (!ControlState, ![DrawFunction]);
  249. ScrollDown width ascent lineH nrVis y state
  250. |    y >= UpBot || noMore    = (StringCS state, []);
  251. |    defId == first`            = Wait ticks (StringCS state`, [scroll,erase,move,drawit,select]);
  252.                             = Wait ticks (StringCS state`, [scroll,erase,move,drawit]);
  253.     where {
  254.         (noMore,first`,item)= GetScrolledDownItem first state;
  255.         state`                = SetFirstIndex first` state;
  256.         first                = GetFirstIndex state;
  257.         defId                = GetDefltIndex state;
  258.         scroll                = CopyRectangle ((0,0),(right,bottom)) (0,lineH);
  259.         right                = ItemWid width;
  260.         bottom                = lineH * dec nrVis;
  261.         erase                = EraseRectangle ((0,top`),(right,bottom`));
  262.         (top`, bottom`)        = If (lineH < 0) (bottom + lineH, bottom) (0, lineH);
  263.         move                = MovePenTo (3,ascent);
  264.         drawit                = DrawString item;
  265.         select                = SelectItem width 0 lineH;
  266.         ticks                 = WaitInterval (UpBot - y);
  267.     };
  268.  
  269. GetScrolledDownItem    :: !Int !String -> (!Bool, !Int, !String);
  270. GetScrolledDownItem index state
  271. |    index == FirstItemIndex    = (True, index, "");
  272.                             = (False, i, state % (i, index`));
  273.     where {
  274.         i        = FindPreviousItemIndex index` state;
  275.         index`    = index-2;
  276.     };
  277.  
  278. ScrollUp :: !Int !Int !Int !Int !Int !String -> (!ControlState, ![DrawFunction]);
  279. ScrollUp width ascent lineH nrVis y state
  280. |    y <= DownTop nrVis lineH ||    noMore    = (StringCS state, []);
  281. |    defId == lastid                        = Wait ticks (StringCS state`,[scroll,erase,move,drawit,select]);
  282.                                         = Wait ticks (StringCS state`,[scroll,erase,move,drawit]);
  283.     where {
  284.         (b, first`, it)        = GetItem first state;
  285.         (noMore,lastid,item)= GetScrolledUpItem (dec nrVis) first` state;
  286.         state`                = SetFirstIndex first` state;
  287.         first                = GetFirstIndex state;
  288.         defId                = GetDefltIndex state;
  289.         scroll                = CopyRectangle ((0,lineH),(right,bottom)) (0,0 - lineH);
  290.         right                = ItemWid width;
  291.         bottom                = nrVis * lineH;
  292.         erase                = EraseRectangle ((0,top`),(right,bottom`));
  293.         (top`, bottom`)        = If (lineH < 0) (lineH, 0) (bottom - lineH, bottom);
  294.         move                = MovePenTo (3,newy + ascent);
  295.         drawit                = DrawString item;
  296.         select                = SelectItem width newy lineH;
  297.         newy                = lineH *  dec nrVis;
  298.         ticks                 = WaitInterval (y - DownTop nrVis lineH );
  299.     };
  300.  
  301. GetScrolledUpItem :: !Int !Int !String -> (!Bool, !Int, !String);
  302. GetScrolledUpItem nr index state
  303. |    nr == 0 || noMore    = (noMore, index, item);
  304.                         = GetScrolledUpItem (dec nr) index` state;
  305.     where {
  306.         (noMore, index`, item) = GetItem index state;
  307.     };
  308.  
  309. CanScroll :: !String -> (!Bool, !Bool);
  310. CanScroll state
  311.     =    (not up, not down);
  312.     where {
  313.         (up,    f2, i2)    = GetScrolledUpItem nrVis first state;
  314.         (down,    f1, i1)    = GetScrolledDownItem first state;
  315.         first            = GetFirstIndex state;
  316.         nrVis            = GetNrVis state;
  317.     };
  318.  
  319. WaitInterval :: !Int -> Int;
  320. WaitInterval i
  321. |    i <= 0    = TicksPerSecond / 6;
  322.             = (TicksPerSecond / inc (i / 5) ) / 6;
  323.  
  324. HiliteArrow :: !Int !Int !Picture -> Picture;
  325. HiliteArrow width top pic
  326.     =    SetPenMode CopyMode (
  327.             FillRectangle ((l,top),(r,b)) (
  328.             SetPenMode XorMode pic));
  329.     where {
  330.         l = inc (ItemWid width);
  331.         r = dec width;
  332.         b = top + ArrowHgt;
  333.     };
  334.  
  335. InItemList :: !Int !Int !Int !Int !Int -> Bool;
  336. InItemList width ht nr x y
  337.     =    x >= 0 && x <= ItemWid width && (y >= 0 && y <= nr * ht);
  338.     
  339. OnUpArrow :: !Int !Int !Int -> Bool;
  340. OnUpArrow width x y
  341.     =    x > ItemWid width && x < width && (y >= UpTop && y <= UpBot);
  342.  
  343. OnDownArrow :: !Int !Int !Int !Int !Int -> Bool;
  344. OnDownArrow width ht nr x y
  345.     =    x > ItemWid width && x < width && (y >= DownTop nr ht && y <= DownBot nr ht);
  346.  
  347.  
  348. /*    The dialog function. */
  349.  
  350. ScrollDFunc    ::    !DialogItemId !(DialogFunction s (IOState s)) !DialogInfo
  351.                 !(DialogState s (IOState s))
  352.             ->      DialogState s (IOState s);
  353. ScrollDFunc id dialogF info dState
  354. |    GetAction cState == Selected    = dialogF info dState;
  355.                                     = dState;
  356.     where {
  357.         (isScrollList, cState)        = GetScrollState id info;
  358.     };
  359.  
  360. GetScrollState :: !DialogItemId !DialogInfo -> (!Bool, !String);
  361. GetScrollState id info = GetScrollStateFromControl (GetControlState id info);
  362.  
  363. GetScrollStateFromControl :: !ControlState -> (!Bool, !String);
  364. GetScrollStateFromControl (StringCS state)    = (True, state); 
  365. GetScrollStateFromControl _                    = (False, "");
  366.  
  367.  
  368. //
  369. //    The function to change the scrolling list.
  370. //
  371.  
  372. ChangeScrollingList    ::    !DialogItemId !ItemTitle ![ItemTitle]
  373.                         !(DialogState s (IOState s))
  374.                     ->      DialogState s (IOState s);
  375. ChangeScrollingList id defItem items dState
  376. |    isScrollList    = ChangeControlState id cState dState`;
  377.                     = ScrollListError "ChangeScrollingList" "Item is not a ScrollingList" id;
  378.     where {
  379.         cState                    = StringCS (SetWidth width state);
  380.         (maxWidth, state)        = InitScrollState font nrVis defItem items;
  381.         width                    = GetWidth oldState;
  382.         (b, font)                = SelectFont name style size;
  383.         (name, style, size)        = DefaultFont;
  384.         nrVis                    = GetNrVis oldState;
  385.         (isScrollList, oldState)= GetScrollState id info;
  386.         (info, dState`)            = DialogStateGetDialogInfo dState;
  387.     };
  388.  
  389.  
  390. //
  391. //    The functions to retrieve the selected item in the scrolling list.
  392. //
  393.  
  394. GetScrollingListItem :: !DialogItemId !DialogInfo -> ItemTitle;
  395. GetScrollingListItem id info
  396. |    isScrollList    = item;
  397.                     = ScrollListError "GetScrollingListItem" "Item is not a ScrollingList" id;
  398.     where {
  399.         (b, i, item)            = GetItem (GetDefltIndex state) state;
  400.         (isScrollList, state)    = GetScrollState id info;
  401.     };
  402.  
  403.  
  404. /*    Access functions to the ControlState. */
  405.  
  406. GetItem    :: !Int !String -> (!Bool, !Int, !String);
  407. GetItem index state
  408. //    -> (TRUE, index, ""),    IF =C (INDEX state index) EndOfList        == alternative changed
  409. |    dec (size state)  == index    = (True, index, "");            // into this one
  410.                                     = (False, inc i, state % (index, dec i));
  411.     where {
  412.         i = NextNlIndex index state;
  413.     };
  414.  
  415. NextNlIndex    :: !Int !String -> Int;
  416. NextNlIndex i str
  417. |    str.[i] == '\n'    = i;
  418.                             = NextNlIndex (inc i) str;
  419.  
  420. FindPreviousItemIndex :: !Int !String -> Int;
  421. FindPreviousItemIndex i str
  422. |    i < FirstItemIndex        = FirstItemIndex;
  423. |    str.[i] == '\n'    = inc i; 
  424.                             = FindPreviousItemIndex (dec i) str;
  425.  
  426. GetAction :: !String -> Char;
  427. GetAction state = state.[ChangeI];
  428.  
  429. SetAction :: !Char !String -> String;
  430. SetAction action state = state := (ChangeI, action);
  431.  
  432. GetNrVis :: !String -> Int;
  433. GetNrVis state = toInt (state.[NrVisI]);
  434.  
  435. GetWidth :: !String -> Int;
  436. GetWidth state = GetNrFromState WidthI state;
  437.  
  438. SetWidth :: !Int !String -> !String;
  439. SetWidth width state = SetNrInState WidthI width state;
  440.  
  441. GetFirstIndex :: !String -> Int;
  442. GetFirstIndex state = GetNrFromState FirstI state;
  443.  
  444. SetFirstIndex :: !Int !String -> String;
  445. SetFirstIndex first state = SetNrInState FirstI first state;
  446.  
  447. GetDefltIndex :: !String -> Int;
  448. GetDefltIndex state = GetNrFromState DefltI state;
  449.  
  450. SetDefltIndex :: !Int !String -> String;
  451. SetDefltIndex deflt state = SetNrInState DefltI deflt state;
  452.  
  453. GetNrFromState :: !Int !String -> Int;
  454. GetNrFromState index state
  455.     =    toInt c0 + 256 * toInt c1;
  456.     where {
  457.         c0 = state.[index];
  458.         c1 = state.[inc index];
  459.     };
  460.  
  461. SetNrInState :: !Int !Int !String -> !String;
  462. SetNrInState index nr state
  463.     =    (state := (index, c0)) := (inc index, c1);
  464.     where {
  465.         c0 = toChar (nr mod 256);
  466.         c1 = toChar (nr / 256);
  467.     };
  468.  
  469.  
  470. /* Misc. functions */
  471.  
  472. MeasureToHorPixels :: !Measure        -> Int;
  473. MeasureToHorPixels (MM        mm)        = MMToHorPixels        mm;
  474. MeasureToHorPixels (Inch    inch)    = InchToHorPixels    inch;
  475. MeasureToHorPixels (Pixel    p)        = p;
  476.